package com.ctg.behavior.calc.impala.calculator;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.ctg.behavior.calc.common.CtSQLParam;
import com.ctg.behavior.calc.impala.CtCalculator;
import com.ctg.behavior.calc.impala.builder.funnel.CtFunnelCalcResultBuilder;
import com.ctg.behavior.calc.impala.builder.funnel.CtFunnelStepReprotBuilder;
import com.ctg.behavior.calc.impala.engine.ImpalaSQLEngine;
import com.ctg.behavior.calc.impala.report.funnel.CtCalcFunnelStepReport;
import com.ctg.behavior.calc.impala.transfer.funnel.CtFunnelStepTransfer;
import com.ctg.behavior.calc.impala.transfer.funnel.CtFunnelStepUnionTransfer;
import com.ctg.behavior.calc.impala.utils.CtCalculatorUtils;
import com.ctg.behavior.client.impala.common.CtQueryResult;
import com.ctg.behavior.common.calc.CtCalcBody;
import com.ctg.behavior.common.calc.CtCalcResult;
import com.ctg.behavior.common.consts.CtCalcTaskConsts;
import com.ctg.behavior.common.funnel.CtFunnelCalcBody;
import com.ctg.behavior.common.funnel.CtFunnelCalcData;
import com.ctg.behavior.common.funnel.CtFunnelCalcResult;
import com.ctg.behavior.common.funnel.CtFunnelDetailBody;
import com.ctg.behavior.utils.CtDateUtils;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
public class CtFunnelCalculator implements CtCalculator {

	@Autowired
	private CtFunnelStepTransfer stepTransfer;
	@Autowired
	private CtFunnelStepUnionTransfer stepUnionTransfer;
	@Autowired
	private ImpalaSQLEngine sqlEngine;
	@Autowired
	private CtFunnelStepReprotBuilder stepReprotBuilder;
	@Autowired
	private CtFunnelCalcResultBuilder calcResultBuilder;

	/****************************************************
	 * @apiNote: 1.漏斗计算是按步骤分步执行SQL
	 * @apiNote: 2.合并每个步骤的结果到CtFunnelCalcResult对象中
	 */
	@Override
	public CtCalcResult doCalculator(CtCalcBody calcBody) {
		CtFunnelCalcResult calcResult = new CtFunnelCalcResult();
		if (!(calcBody instanceof CtFunnelCalcBody)) {
			log.error("calcBody={}", calcBody.getClass());
			calcResult.setSuccess(false);
			calcResult.setErrorMessage("calcBody class type error.");
			return calcResult;
		}
		CtFunnelCalcData calcData = new CtFunnelCalcData();
		calcResult.setValue(calcData);

		log.info("doBuilder-start: {}", CtDateUtils.getCurrentDateSSS());
		CtFunnelCalcBody funnelCalcBody = (CtFunnelCalcBody) calcBody;
		calcData.setByFields(funnelCalcBody.getByFields());
		// 1. 校验漏斗详细信息(漏斗步骤)
		{
			CtFunnelDetailBody funnelDetailBody = funnelCalcBody.getFunnelDetail();
			if (null == funnelDetailBody) {
				log.error("funnel is null, calcBody={}", JSON.toJSONString(funnelCalcBody));
				calcResult.setSuccess(false);
				calcResult.setErrorMessage("funnel is null");
				return calcResult;
			}
			if (funnelDetailBody.getSteps().isEmpty() || funnelDetailBody.getSteps().size() < 2) {
				log.error("funnel step is empty, calcBody={}", JSON.toJSONString(funnelCalcBody));
				calcResult.setSuccess(false);
				calcResult.setErrorMessage("funnel step is empty");
				return calcResult;
			}
		}
		// 2. 组建Impala SQL计算对象
		List<CtCalcFunnelStepReport> steps = stepReprotBuilder.doBuilder(funnelCalcBody);
		//
		calcResultBuilder.resetResultBuilderThreadLocal();
		log.info("doBuilder-end: {}", CtDateUtils.getCurrentDateSSS());

		// 3. 执行计算
		log.info("time - start: {}", CtDateUtils.getCurrentDateSSS());
		CtCalcFunnelStepReport lastStepReport = null;
		stepUnionTransfer.resetIndexedThreadLocal();
		for (CtCalcFunnelStepReport funnelStep : steps) {
			log.info("one-time-start: {}", CtDateUtils.getCurrentDateSSS());
			// 1.1转换成SQL
			log.info("one-report={}", JSON.toJSONString(funnelStep));
			// CtSQLParam sqlParam = new CtSQLParam();
			String oneStepSql = "";
			if (funnelStep.getStepNo() == 0) {
				oneStepSql = stepTransfer.doTransfer(funnelStep, CtSQLParam.createParam());
			} else {
				oneStepSql = stepUnionTransfer.doTransfer(funnelStep, lastStepReport);
			}
			lastStepReport = funnelStep;
			log.info("one-sql={}", oneStepSql);
			// 1.2执行SQL
			// 1.3查询类型
			String queryType = CtCalcTaskConsts.TASK_TYPE_FUNNEL;
			queryType = queryType + "@" + funnelStep.getEventId();
			// 1.4执行查询结果
			CtQueryResult queryResult = sqlEngine.doQuery(queryType, oneStepSql);
			log.info("one-queryResult={}", JSON.toJSONString(queryResult));

			CtCalculatorUtils.fillCalcResult(calcResult, queryResult);
			if (!calcResult.getSuccess()) {
				log.error(queryResult.getCode());
				break;
			}

			// 1.5解析步骤结果，并追加到上一次结果中
			calcData = calcResultBuilder.doBuilder(calcData, queryResult.getRows(), funnelStep);
			log.info("one-result={}", JSON.toJSONString(queryResult));
			log.info("one-time-end: {}", CtDateUtils.getCurrentDateSSS());
		}
		log.info("time - end: {}", CtDateUtils.getCurrentDateSSS());
		return calcResult;
	}

}
